//By Francois Budin
#ifndef Vector_cxx
#define Vector_cxx


#include "Vector.h"


namespace FPTK
{


    template<class T>
    Vector<T>::Vector(long N):TabND<T>(1,N)
    {
    }

    template<class T>
    Vector<T>::~Vector()
    {
    }


    template<class T>
    Vector<T> Vector<T>::operator+(const Vector<T> &v2) const
    {
        Exception ex("Vector::operator+","Vectors must have the same size");
        if(v2.GetSizeDim(0)!=GetSizeDim(0)) throw ex;
        Vector<T> tmp(GetSizeDim(0));
        for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
        {
            tmp.SetElement(GetElement(i)+v2.GetElement(i),i);
        }
        return tmp;
    }



    template<class T>
    Vector<T> Vector<T>::operator-(const Vector<T> &v2) const
    {
        Exception ex("Vector::operator+","Vectors must have the same size");
        if(v2.GetSizeDim(0)!=GetSizeDim(0)) throw ex;
        Vector<T> tmp(GetSizeDim(0));
        for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
        {
            tmp.SetElement(GetElement(i)-v2.GetElement(i),i);
        }
        return tmp;
    }



template<class T> template<class C>
Vector<T>::operator Vector<C> const() const
{
   Vector<C> tmp(GetSizeDim(0));
   for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
   {
      tmp.SetElement((C)GetElement(i),i);
   }
   return tmp;
}


template<class T> template<class C>
Vector<T> Vector<T>::operator*(C f) const
{
   Vector<T> tmp(GetSizeDim(0));
   for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
   {
      tmp.SetElement(GetElement(i)*T(f),i);
   }
   return tmp;
}

    //template<class T>
    //Vector<T> Vector<T>::operator*(float f) const
    //{
    //    Vector<T> tmp(GetSizeDim(0));
    //    for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
    //    {
    //        tmp.SetElement(GetElement(i)*T(f),i);
    //    }
    //    return tmp;
    //}

    //template<class T>
    //Vector<T> Vector<T>::operator*(double d) const
    //{
    //    Vector<T> tmp(GetSizeDim(0));
    //    for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
    //    {
    //        tmp.SetElement(GetElement(i)*T(d),i);
    //    }
    //    return tmp;
    //}

    //template<class T>
    //Vector<T> Vector<T>::operator*(short s) const
    //{
    //    Vector<T> tmp(GetSizeDim(0));
    //    for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
    //    {
    //        tmp.SetElement(GetElement(i)*T(s),i);
    //    }
    //    return tmp;
    //}


    //template<class T>
    //Vector<T> Vector<T>::operator*(long l) const
    //{
    //    Vector<T> tmp(GetSizeDim(0));
    //    for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
    //    {
    //        tmp.SetElement(GetElement(i)*T(in),i);
    //    }
    //    return tmp;
    //}

    //template<class T>
    //Vector<T> Vector<T>::operator*(int in) const
    //{
    //    Vector<T> tmp(GetSizeDim(0));
    //    for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
    //    {
    //        tmp.SetElement(GetElement(i)*T(in),i);
    //    }
    //    return tmp;
    //}


    template<class T>
    Vector<T> Vector<T>::operator-()
    {
        Vector<T> tmp(GetSizeDim(0));
        for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
        {
            tmp.SetElement(-GetElement(i),i);
        }
        return tmp;
    }


    template<class T>
    double Vector<T>::GetNorm(long p) const
    {
        double tmp=0;
        if(p<1) return -1;
        for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
        {
            tmp+=pow(abs(GetElement(i)),p);
        }
        tmp=pow(tmp,double(1)/double(p));
        return tmp;
    }

    template<class T>
    double Vector<T>::GetNorm() const
    {
        return GetNorm(2);
    }

    template<class T>
    double Vector<T>::GetNormInfini() const
    { 
        double tmp=0;
        for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
        {
            double tmp2=abs(GetElement(i));
            if(tmp2>tmp) tmp=tmp2;
        }
        return tmp;
    }

    template<class T>
    double Vector<T>::DotProduct(const Vector<T> &v2) const
    {
        Exception ex("Vector::operator+","Vectors must have the same size");
        if(v2.GetSizeDim(0)!=GetSizeDim(0)) throw ex;
        double tmp=0;
        for(unsigned long i=0;i<unsigned long(GetSizeDim(0));i++)
        {
            tmp+=GetElement(i)*v2.GetElement(i);
        }
        return tmp;
    }

    template<class T>
    Vector<T> Vector<T>::CrossProduct(const Vector<T> &v2) const
    {
        Exception ex2("Vector::CrossProduct","Cross Product only in 3D");
        Exception ex("Vector::operator+","Vectors must have the same size");
        if(v2.GetSizeDim(0)!=GetSizeDim(0)) throw ex;
        Vector<T> tmp(GetSizeDim(0));
        tmp.Zeros();
        if(GetSizeDim(0)==3)
        {
            tmp.SetElement(GetElement(1)*v2.GetElement(2)-GetElement(2)*v2.GetElement(1),0);
            tmp.SetElement(GetElement(2)*v2.GetElement(0)-GetElement(0)*v2.GetElement(2),1);
            tmp.SetElement(GetElement(0)*v2.GetElement(1)-GetElement(1)*v2.GetElement(0),2);
        }
        else throw ex2;
        return tmp;
    }



}//end namespace FPTK

#endif

